Docker Compose基础

使用微服务架构的应用系统一般包含若干个微服务,每个微服务一般都会部署多个实例,若每个微服务都要手动启停,效率很低、维护量很大。可使用Docker Compose来轻松、高效地管理容器。Docker Compose是一个用于定义和运行多容器的Docker应用的工具,使用Compose可在一个yaml格式的配置文件中配置应用服务,使用一个命令,即可创建并启动配置中引用的所有服务。

Docker Compose的安装有多种方式,可通过Shell安装pip安装作为容器安装等,以下是通过Shell安装:

1
2
3
4
# docker compose安装步骤
sudo curl -L "https://github.com/docker/compose/releases/download/1.28.6/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
docker-compose --version

Docker Compose的使用只需要编写一个描述容器的配置docker-compose.yml配置文件,然后使用描述对容器的操作的docker-compose命令操作即可。

这里依然使用eureka-server-0.0.1-SNAPSHOT.jar,在该jar所在目录的上一级目录中创建docker-compose.yml配置文件文件,在该配置文件中配置如下:

1
2
3
4
5
6
7
8
9
10
version: '3.8'
services:
eureka: #指定服务名
image: eleven-eureka-server:0.0.1 #指定镜像名称
build: ./eureka #指定Dockfile所在路径
container_name: eleven-eureka-server #指定启动容器名称
ports:
- "8761:8761" #指定端口映射
expose:
- 8761 #声明容器对外暴露的端口

然后在docker-compose.yml配置文件文件所在路径执行docker-compose up启动服务,使用compose启动时会先创建一个默认的网络app_default,默认以compose所在文件目录名加_default命名,compose内的所有容器都会加入此网络可用服务名相互访问,若镜像eleven-eureka-server:0.0.1不存在则先构建镜像,若镜像存在则不构建,加上--build参数可强制先构建镜像,若镜像之前构建过且构建文件没有变化或构建的内容没有变化,就算加上–build参数也不会重新构建,根据构建的镜像创建一个名称叫app_eureka_1的容器,appdocker-compose.yml配置文件文件所在目录,最后启动容器

1
2
3
# -d用于设置后台启动
docker-compose up -d
docker-compose up -d --build

Docker Compose将所管理的容器分为工程服务器三层,Docker Compose运行目录下的所有文件包括docker-compose.ymlextends文件环境变量文件组成一个工程默认为docker-compose.yml所在目录的目录名称一个工程可包含多个服务,每个服务中定义了容器运行的镜像参数依赖一个服务可包括多个容器实例

同一个docker compose内部的容器之间可用服务名相互访问服务名相当于hostname可直接ping服务名,得到的就是服务对应容器的ip,若服务做了扩容一个服务对应了多个容器,则ping服务名会轮询访问服务对应的每台容器ip ,Docker底层用了LVS等技术实现该负载均衡。

docker-compose.yml常用指令

可以参考docker-compose.yml文件官方文档

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# image指定镜像名称或镜像id,若该镜像在本地不存在,Compose会尝试pull下来
image: java
# 指定Dockerfile文件的路径
build: ./dir
# build也可以是一个对象,用以指定Dockerfile和参数
build:
context: ./dir
dockerfile: Dockerfile-alternate
args:
buildno: 1
# 覆盖容器启动后默认执行的命令
command: bundle exec thin -p 3000
# command也可以是一个list,类似于Dockerfile中的CMD指令
command: [bundle, exec, thin, -p, 3000]
# links显示链接到其他服务中的容器,可指定服务名称和链接的别名使用SERVICE:ALIAS的形式,或者只指定服务名称
links:
- db
- db:database
- redis
# 表示链接到docker-compose.yml外部的容器,甚至并非Compose管理的容器,特别是对于那些提供共享容器或共同服务
external_links:
- redis_1
- project_db_1:mysql
- project_db_1:postgresql
# 暴露端口信息,使用宿主端口:容器端口的格式,或者仅指定容器端口此时宿主机将会随机指定端口,类似于docker run -p
ports:
- "3000"
- "3000-3005"
- "8000:8000"
- "9090-9091:8080-8081"
- "49100:22"
- "127.0.0.1:8001:8001"
- "127.0.0.1:5000-5010:5000-5010"
# 暴露端口,只将端口暴露给连接的服务,而不暴露给宿主机
expose:
- "3000"
- "8000"
# 卷挂载路径设置,可设置宿主机路径HOST:CONTAINER或加上访问模式HOST:CONTAINER:ro
volumes:
# Just specify a path and let the Engine create a volume
- /var/lib/mysql
# Specify an absolute path mapping
- /opt/data:/var/lib/mysql
# Path on the host, relative to the Compose file
- ./cache:/tmp/cache
# User-relative path
- ~/configs:/etc/configs/:ro
# Named volume
- datavolume:/var/lib/mysql
# 从另一个服务或者容器挂载卷。可指定只读或可读写,若访问模式未指定,则默认是可读写
volumes_from:
- service_name
- service_name:ro
- container:container_name
- container:container_name:rw
# 设置环境变量,可使用数组或字典,只有一个key的环境变量可在运行Compose的机器上找到对应的值,这有助于加密的或特殊主机的值
environment:
RACK_ENV: development
SHOW: 'true'
SESSION_SECRET:
environment:
- RACK_ENV=development
- SHOW=true
- SESSION_SECRET
# 从文件中获取环境变量,可为单独的文件路径或列表,若通过docker-compose -f FILE指定了模板文件,则env_file中路径会基于模板文件路径,若有变量名称与environment指令冲突,则以envirment为准
env_file: .env
env_file:
- ./common.env
- ./apps/web.env
- /opt/secrets.env
# extends继承另一个服务,基于已有的服务进行扩展
# 设置网络模式
net: "bridge"
net: "host"
net: "none"
net: "container:[service name or container name/id]"
# 配置dns服务器,可为一个值,也可为一个列表
dns: 8.8.8.8
dns:
- 8.8.8.8
- 9.9.9.9
# 配置DNS搜索域,可以是一个值,也可以是一个列表
dns_search: example.com
dns_search:
- dc1.example.com
- dc2.example.com
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
version: '3.8'
services:
mysql:
image: mysql:5.7
container_name: mysql
# 覆盖容器启动后默认执行的启动mysql命令
command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
restart: always # 关机或者重启机器时,docker同时重启容器,一般mysql服务可这么设置,保持服务一直都在
environment:
MYSQL_ROOT_PASSWORD: root # 设置root帐号密码
ports:
- 3306:3306
volumes:
- /data/mysql/data/db:/var/lib/mysql # 数据文件挂载
- /data/mysql/data/conf:/etc/mysql/conf.d # 配置文件挂载
- /data/mysql/log:/var/log/mysql # 日志文件挂载
- /etc/localtime:/etc/localtime:ro #同步宿主机与容器时间,ro代表readonly只读

redis:
image: redis:5.0
container_name: redis
command: redis-server --appendonly yes
volumes:
- /data/redis/data:/data # 数据文件挂载
ports:
- 6379:6379

rabbitmq:
image: rabbitmq:3.7.25-management
container_name: rabbitmq
volumes:
- /data/rabbitmq/data:/var/lib/rabbitmq # 数据文件挂载
- /data/rabbitmq/log:/var/log/rabbitmq # 日志文件挂载
ports:
- 5672:5672
- 15672:15672

elasticsearch:
image: elasticsearch:6.4.0
container_name: elasticsearch
environment:
- "cluster.name=elasticsearch" # 设置集群名称为elasticsearch
- "discovery.type=single-node" # 单一节点模式启动
- "ES_JAVA_OPTS=-Xms512m -Xmx512m" # 置使用jvm内存大小,稍微配置大点,不然有可能启动不成功
volumes:
- /data/elasticsearch/plugins:/usr/share/elasticsearch/plugins # 插件文件挂载
- /data/elasticsearch/data:/usr/share/elasticsearch/data # 数据文件挂载
ports:
- 9200:9200
- 9300:9300

kibana:
image: kibana:6.4.0
container_name: kibana
# 一个compose文件管理的服务可直接用服务名访问,若给服务取别名则可用links实现,如下面的es就是elasticsearch服务别名
links:
- elasticsearch:es # 用es这个域名访问elasticsearch服务
depends_on:
- elasticsearch # kibana在elasticsearch启动之后再启动
environment:
- "elasticsearch.hosts=http://es:9200" # 设置访问elasticsearch的地址
ports:
- 5601:5601

logstash:
image: logstash:6.4.0
container_name: logstash
volumes:
# 挂载logstash的配置文件,docker对单个文件的挂载需要先在宿主机建好对应文件才能挂载成功
- /data/logstash/logstash-springboot.conf:/usr/share/logstash/pipeline/logstash.conf
depends_on:
- elasticsearch # kibana在elasticsearch启动之后再启动
links:
- elasticsearch:es # 可用es这个域名访问elasticsearch服务
ports:
- 4560:4560

mongo:
image: mongo:3.2
container_name: mongo
volumes:
- /data/mongo/db:/data/db # 数据文件挂载
ports:
- 27017:27017

nacos:
image: nacos/nacos-server:1.4.2
container_name: nacos
environment:
- MODE=standalone
volumes:
- /data/nacos/logs/:/home/nacos/logs
ports:
- "8848:8848"

zookeeper:
image: zookeeper:3.5
ports:
- 2181:2181
volumes:
- /data/zookeeper/data:/data
- /data/zookeeper/conf:/conf

rocketmq:
image: rocketmqinc/rocketmq
container_name: rocketmq
restart: always
ports:
- 9876:9876
volumes:
- /data/rocketmq/logs:/home/rocketmq/logs
- /data/rocketmq/store:/home/rocketmq/store
command: sh mqnamesrv

broker:
image: rocketmqinc/rocketmq
container_name: rmqbroker
restart: always
ports:
- 10909:10909
- 10911:10911
- 10912:10912
volumes:
- /data/rocketmq/logs:/home/rocketmq/logs
- /data/rocketmq/store:/home/rocketmq/store
# 该配置需要先在宿主机对应目录放好broker.conf配置文件,文件内容参考下面文档
- /data/rocketmq/conf/broker.conf:/opt/rocketmq-4.4.0/conf/broker.conf
command: sh mqbroker -n namesrv:9876 -c ../conf/broker.conf
depends_on:
- rocketmq
environment:
- JAVA_HOME=/usr/lib/jvm/jre

console:
image: styletang/rocketmq-console-ng
container_name: rocketmq-console-ng
restart: always
ports:
- 8076:8080
depends_on:
- rocketmq
environment:
- JAVA_OPTS= -Dlogging.level.root=info -Drocketmq.namesrv.addr=rocketmq:9876
- Dcom.rocketmq.sendMessageWithVIPChannel=false
1
2
3
4
5
6
7
8
brokerName = broker-a
brokerId = 0
deleteWhen = 04
fileReservedTime = 48
brokerRole = ASYNC_MASTER
flushDiskType = ASYNC_FLUSH
# 宿主机IP
brokerIP1=192.168.65.42

docker-compose命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 查看compose内的容器
docker-compose -f docker-compose-app.yml ps
# 关闭或启动或重启compose内的某个容器
docker-compose -f docker-compose-app.yml stop|start|restart <服务名>
# 关闭或重启compose所有容器
docker-compose -f docker-compose-app.yml stop|restart
# 查看compose所有容器的运行日志
docker-compose -f docker-compose-app.yml logs -f
# 查看compose下某个容器的运行日志
docker-compose -f docker-compose-app.yml logs -f <服务名>
# 也可以把compose的容器日志输出到日志文件里去,然后用tail -f随时查看
docker-compose -f docker-compose-app.yml logs -f >> myDockerCompose.log &
# 重新构建有变化的镜像并更新到容器再启动
docker-compose -f docker-compose-app.yml up --build -d
# 重新创建docker-compose.yml配置有变化的容器并启动
docker-compose -f docker-compose-app.yml up --force-recreate -d
# 停掉容器再删除容器
docker-compose -f docker-compose-app.yml down
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
version: '3.8'
services:
eleven-auth: # 指定服务名
image: eleven-auth:0.0.1 # 指定镜像名称
build: ./eleven # 指定Dockfile所在路径
container_name: eleven-auth # 指定启动容器名称
ports:
- "8888:8888" # 指定端口映射
expose:
- 8888 # 声明容器对外暴露的端口
environment:
- JAVA_TOOL_OPTIONS=-Xmx1g -Xms1g -XX:MaxMetaspaceSize=512m -javaagent:/agent/skywalking-agent.jar -DSW_AGENT_NAME=eleven-auth -DSW_AGENT_COLLECTOR_BACKEND_SERVICES=192.168.0.180:11800
# 访问不在同一个compose文件管理的服务需要用external_links,前提是这些服务都在同一个网络下才能正常访问
external_links:
- nacos:nacos # 可用nacos这个域名访问nacos服务
- mysql:db # 可用db这个域名访问mysql服务
cap_add:
- SYS_PTRACE # 该参数让docker能支持在容器里能执行jdk自带的类似jinfo,jmap这些命令
eleven-user: # 指定服务名
image: eleven-user:0.0.1 # 指定镜像名称
build: ./eleven # 指定Dockfile所在路径
container_name: eleven-user # 指定启动容器名称
ports:
- "8877:8877" # 指定端口映射
expose:
- 8877 # 声明容器对外暴露的端口
environment:
- JAVA_TOOL_OPTIONS=-Xmx1g -Xms1g -XX:MaxMetaspaceSize=512m -javaagent:/agent/skywalking-agent.jar -DSW_AGENT_NAME=eleven-user -DSW_AGENT_COLLECTOR_BACKEND_SERVICES=192.168.0.180:11800
# 访问不在同一个compose文件管理的服务需要用external_links,前提是这些服务都在同一个网络下才能正常访问
external_links:
- nacos:nacos # 可用nacos这个域名访问nacos服务
- mysql:db # 可用db这个域名访问mysql服务
- mongo
- redis
- rabbitmq
cap_add:
- SYS_PTRACE # 该参数让docker能支持在容器里能执行jdk自带的类似jinfo,jmap这些命令
depends_on:
- eleven-auth # authcenter启动之后再启动

有时需要扩容微服务,则需要将docker-compose.yml里的服务的端口映射容器名称都注释掉,因为不可能两个服务的容器映射到宿主机的同一个端口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
version: '3.8'
services:
eleven-auth: # 指定服务名
image: eleven-auth:0.0.1 # 指定镜像名称
build: ./eleven # 指定Dockfile所在路径
container_name: eleven-auth # 指定启动容器名称
ports:
- "8888:8888" # 指定端口映射
expose:
- 8888 # 声明容器对外暴露的端口
environment:
- JAVA_TOOL_OPTIONS=-Xmx1g -Xms1g -XX:MaxMetaspaceSize=512m -javaagent:/agent/skywalking-agent.jar -DSW_AGENT_NAME=eleven-auth -DSW_AGENT_COLLECTOR_BACKEND_SERVICES=192.168.0.180:11800
# 访问不在同一个compose文件管理的服务需要用external_links,前提是这些服务都在同一个网络下才能正常访问
external_links:
- nacos:nacos # 可用nacos这个域名访问nacos服务
- mysql:db # 可用db这个域名访问mysql服务
cap_add:
- SYS_PTRACE # 该参数让docker能支持在容器里能执行jdk自带的类似jinfo,jmap这些命令
eleven-user: # 指定服务名
image: eleven-user:0.0.1 # 指定镜像名称
build: ./eleven # 指定Dockfile所在路径
# container_name: eleven-user # 指定启动容器名称
# ports:
# - "8877:8877" # 指定端口映射
# expose:
# - 8877 # 声明容器对外暴露的端口
environment:
- JAVA_TOOL_OPTIONS=-Xmx1g -Xms1g -XX:MaxMetaspaceSize=512m -javaagent:/agent/skywalking-agent.jar -DSW_AGENT_NAME=eleven-user -DSW_AGENT_COLLECTOR_BACKEND_SERVICES=192.168.0.180:11800
# 访问不在同一个compose文件管理的服务需要用external_links,前提是这些服务都在同一个网络下才能正常访问
external_links:
- nacos:nacos # 可用nacos这个域名访问nacos服务
- mysql:db # 可用db这个域名访问mysql服务
- mongo
- redis
- rabbitmq
cap_add:
- SYS_PTRACE # 该参数让docker能支持在容器里能执行jdk自带的类似jinfo,jmap这些命令
depends_on:
- eleven-auth # authcenter启动之后再启动
deploy:
replicas:2

执行如下扩容命令,服务一旦扩容对应了多个容器,则访问服务名docker会自动负载均衡去访问服务对应的每台容器,docker compose主要用在单物理机内扩容的情况,要做多机扩容还需自己在多个机器上做很多定制化配置,做多物理机扩容一般都会用docker swarmkubernetes

1
2
3
4
5
# 必须先正常编排微服务,然后才能动态扩容,文件有变动,需要重新创建容器
docker-compose -f docker-compose-app.yml up --force-recreate -d
docker-compose -f docker-compose-app.yml scale eleven-user=2
# 如果要缩容执行如下操作
docker-compose -f docker-compose-app.yml scale eleven-user=1